package cc.admin.modules.sys.service.impl;

import cc.admin.common.db.util.TenantUtil;
import cc.admin.common.exception.CcAdminException;
import cc.admin.common.sys.vo.LoginUser;
import cc.admin.common.util.PasswordUtil;
import cc.admin.common.util.oConvertUtils;
import cc.admin.modules.sys.entity.SysCompany;
import cc.admin.modules.sys.mapper.SysCompanyMapper;
import cc.admin.modules.sys.mapper.SysRolePermissionMapper;
import cc.admin.modules.sys.service.ISysCompanyService;
import cc.admin.modules.sys.service.ISysUserService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.util.Assert;
import org.dom4j.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @Description: 动态表单
 * @Author: cc-admin
 * @Date: 2021-11-17
 * @Version: V1.0.0
 */
@Service
@Slf4j
public class SysCompanyServiceImpl extends ServiceImpl<SysCompanyMapper, SysCompany> implements ISysCompanyService {

	@Autowired
	JdbcTemplate jdbcTemplate;
	@Autowired
	SysCompanyMapper sysCompanyMapper;
	//角色和权限
	@Autowired
	SysRolePermissionMapper sysRolePermissionMapper;

	private String dbName = null;

	@Autowired
	private ISysUserService sysUserService;

	@Value(value = "${ureport.fileStoreDir}")
	private String file;

	@Value(value = "${ureport.fileStoreDir}")
	private String fileUrl;

	/**
	 * 复制一份表
	 *
	 * @param tableName
	 * @param companyId
	 */
	public void copyTableData(String tableName, String companyId) {
		String sql = getInsertSelectSql(tableName, companyId);
		System.out.println(sql);
		jdbcTemplate.execute(String.format("delete from %s where tenant_id = '%s'", tableName, companyId));
		jdbcTemplate.execute(sql);
	}

	private String getDbName() {
		String dbName = "";
		Connection connection = null;
		try {
			DataSource dataSource = jdbcTemplate.getDataSource();
			connection = dataSource.getConnection();
			dbName = connection.getCatalog();
		} catch (SQLException e) {
			e.printStackTrace();
			CcAdminException.runTimeException("获取数据库名称失败！");
		} finally {
			try {
				if (connection != null) {
					connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return dbName;
	}

	public String getInsertSelectSql(String tableName, String companyId) {
		if (StrUtil.isEmpty(this.dbName)) {
			this.dbName = getDbName();
		}
		// 这个是鑫业的ID
		String templateId = "a01";
		List<Map<String, Object>> columnList = jdbcTemplate.queryForList("select column_name from information_schema.columns where table_schema = ? and table_name = ?", this.dbName, tableName);
		StringBuilder insertBuilder = new StringBuilder("insert into ");
		insertBuilder.append(tableName).append("(");
		StringBuilder selectBuilder = new StringBuilder("select ");
		for (int i = 0; i < columnList.size(); i++) {
			Map<String, Object> column = columnList.get(i);
			Object columnName = column.get("column_name");
			if (i > 0) {
				selectBuilder.append(",");
				insertBuilder.append(",");
			}
			if ("tenant_id".equals(columnName)) {
				selectBuilder.append("'").append(companyId).append("'");
				insertBuilder.append(columnName);
			} else {
				selectBuilder.append(columnName);
				insertBuilder.append(columnName);
			}

		}
		insertBuilder.append(") ");
		selectBuilder.append(" from ").append(tableName).append(" where tenant_id='").append(templateId).append("'");
		insertBuilder.append(selectBuilder);
		return insertBuilder.toString();
	}

	/**
	 * 复制报表数据
	 *
	 * @param fromCompany
	 * @param toCompany
	 */
	public void copyUReportFiles(String fromCompany, String toCompany) {
		String fromFolder = file + "/" + fromCompany;
		String toFolder = file + "/" + toCompany;
		FileUtil.del(toFolder);
		FileUtil.copyFilesFromDir(new File(fromFolder), new File(toFolder), true);
		// 需要修改xml中所有的表名，将a01改成对应的公司编号
		dealUReportFiles(fromCompany, toCompany);
	}

	public void dealUReportFiles(String fromCompany, String toCompany) {
		try {
			String path = file + "/" + toCompany;
			//String path = "D:\\opt\\multiship\\UReport\\a02";
			List<String> fileList = FileUtil.listFileNames(path);
			for (String file : fileList) {
				if (file.endsWith(".ureport.xml")) {
					String fullPath = path + "/" + file;
					log.info("处理文件:{}", fullPath);
					String content = FileUtil.readString(fullPath, "UTF-8");
					content = TenantUtil.replaceTenantTableName(content, toCompany);
					FileUtil.writeString(content, fullPath, "UTF-8");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			CcAdminException.runTimeException("处理报表文件出错");
		}
	}

	public static void main(String[] args) throws DocumentException, IOException {
		new SysCompanyServiceImpl().dealUReportFiles("a01", "a02");
	}

	/**
	 * 复制表
	 *
	 * @param tableName
	 * @param companyId
	 */
	public void copyTable(String tableName, String companyId) {
		String newTableName = getNewTableName(tableName, companyId);
		jdbcTemplate.execute(String.format("drop table IF EXISTS %s", newTableName));
		jdbcTemplate.execute(String.format("CREATE TABLE %s LIKE %s", newTableName, tableName));
	}

	/**
	 * 复制表数据，从原来的表，到新表
	 *
	 * @param tableName
	 * @param companyId
	 */
	public void copyTableDataFromTo(String tableName, String companyId) {
		String newTableName = getNewTableName(tableName, companyId);
		jdbcTemplate.execute(String.format("INSERT INTO %s SELECT * FROM %s", newTableName, tableName));
		jdbcTemplate.execute(String.format("update %s set tenant_id = '%s'", newTableName, companyId));
	}

	public String getNewTableName(String tableName, String companyId) {
		return tableName.replaceAll("a01", companyId);
	}

	@Override
	public void addCompany(SysCompany sysCompany) {
		//获取当前登录用户
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		// 公司编码当ID来用
		String companyId = sysCompany.getId();
		addAdmin(sysCompany);
		saveCompany(sysCompany);
		copyUReportFiles(sysUser.getCompanyCode(), companyId);
		// 复制定时任务
		copyQuartz(sysUser.getCompanyCode(), companyId);
	}

	private void copyQuartz(String companyCode, String companyId) {
		List<Map<String, Object>> quartzList = jdbcTemplate.queryForList(String.format("select id from sys_quartz_job where tenant_id='%s'", companyCode));
		// 重新生成ID然后复制一下
		String insertQuartzSql = "insert into sys_quartz_job(id, create_by, create_time, del_flag, update_by, update_time, job_class_name, cron_expression, parameter, description, status, sys_org_code, tenant_id) select '%s' id, create_by, create_time, del_flag, update_by, update_time, job_class_name, cron_expression, parameter, description, status, sys_org_code,'%s'  tenant_id from sys_quartz_job where id = '%s'";
		String insertQuartzJobDetailsSql = "insert into qrtz_job_details(sched_name, job_name, job_group, description, job_class_name, is_durable, is_nonconcurrent, is_update_data, requests_recovery, job_data) select sched_name,'%s' job_name,'%s' job_group, description, job_class_name, is_durable, is_nonconcurrent, is_update_data, requests_recovery, job_data from qrtz_job_details where job_name = '%s'";
		String insertQuartzTriggersSql = "insert into qrtz_triggers(sched_name, trigger_name, trigger_group, job_name, job_group, description, next_fire_time, prev_fire_time, priority, trigger_state, trigger_type, start_time, end_time, calendar_name, misfire_instr, job_data) select sched_name,'%s' trigger_name,'%s' trigger_group,'%s' job_name,'%s' job_group, description, next_fire_time, prev_fire_time, priority, trigger_state, trigger_type, start_time, end_time, calendar_name, misfire_instr, job_data from qrtz_triggers where job_name = '%s'";
		String insertQuartzCronTriggersSql = "insert into qrtz_cron_triggers(sched_name, trigger_name, trigger_group, cron_expression, time_zone_id) select sched_name,'%s' trigger_name,'%s' trigger_group, cron_expression, time_zone_id from qrtz_cron_triggers where trigger_name = '%s'";
		for (Map<String, Object> quartz : quartzList) {
			String id = (String) quartz.get("id");
			String jobId = IdUtil.objectId();
			jdbcTemplate.execute(String.format(insertQuartzSql, jobId, companyId, id));
			// 开始复制job
			jdbcTemplate.execute(String.format(insertQuartzJobDetailsSql, jobId, companyId, id));
			jdbcTemplate.execute(String.format(insertQuartzTriggersSql, jobId, companyId, jobId, companyId, id));
			jdbcTemplate.execute(String.format(insertQuartzCronTriggersSql, jobId, companyId, id));
		}

	}

	private void saveCompany(SysCompany sysCompany) {
		//获取当前登录用户
		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
		String companyId = sysCompany.getId();
		sysCompany.setSysOrgCode(companyId);
		sysCompany.setId(companyId);
		sysCompany.setCreateBy(sysUser.getUsername());
		jdbcTemplate.execute(String.format("delete from sys_company where id='%s'", companyId));
		//创建公司
		sysCompanyMapper.insert(sysCompany);
	}

	/**
	 * 创建管理员账号
	 *
	 * @param sysCompany
	 */
	private void addAdmin(SysCompany sysCompany) {
		String userName = sysCompany.getContactTelephone();
		// 首先验证用户名字为正常状态的不存在
		Assert.isTrue(!sysUserService.checkUserExist(userName), "用户已经存在!");
		String realName = sysCompany.getContact();
		String password = "123456";
		String salt = oConvertUtils.randomGen(8);
		String passwordEncode = PasswordUtil.encrypt(sysCompany.getContactTelephone(), password, salt);
		String userId = IdUtil.objectId();
		String insertUser = "INSERT INTO sys_user(id, username, realname, password, salt, avatar, birthday, sex, email, phone, status, del_flag, third_id, third_type, post, post_name, activiti_sync, work_no, post_id, telephone, create_by, create_time, update_by, update_time, user_identity, duty_ids, id_card, type, ship_type, is_admin, sys_org_code, sys_dept_code, sys_dept_name, sub_sys_code, depart_ids, user_flag, ship_id, ship_id_text, duty_names, duration_days, start_time, end_time, ship_type_name, license_status, license_time, tenant_id) VALUES " +
				"('%s', '%s', '%s', '%s', '%s', null, '1988-12-05 00:00:00', 1, '', '', 1, 0, NULL, NULL, NULL, NULL, 1, '00001', '总经理', NULL, NULL, '2022-02-21 17:54:10', 'admin', '2023-07-28 14:53:43', 2, NULL, '123123199809091231', '3', '05', '1', 'a01', 'a01_a01', '岸基', '02', NULL, '0', NULL, NULL, NULL, NULL, '%s', '2099-07-20 10:23:54', '其他货船', 1, '2099-07-20 10:23:54', '%s')";
		String insertUserSql = String.format(insertUser, userId, userName, realName, passwordEncode, salt, DateUtil.now(), sysCompany.getId());
		System.out.println(insertUserSql);
		jdbcTemplate.execute(String.format("delete from sys_user where tenant_id = '%s'", sysCompany.getId()));
		jdbcTemplate.execute(insertUserSql);
	}

	@Override
	public void deleteCompany(String id) {
		SysCompany sysCompany = sysCompanyMapper.selectById(id);
//        删除工作流
		String sql = "select id from dyn_form where sys_org_code='" + sysCompany.getId() + "'";
		List<String> number = jdbcTemplate.queryForList(sql, String.class);
		StringBuilder oldNumber = new StringBuilder();
		for (String num : number) {
			if (oldNumber.length() > 0) {
				oldNumber.append(",");
			}
			oldNumber.append("\"" + num + "\"");
		}
		int i = oldNumber.length();
		if (oldNumber.length() > 0) {
			String deleteWorkflowSql = "delete from flow_def where id in (" + oldNumber + ")";
			jdbcTemplate.update(deleteWorkflowSql);
		}
		deleteBySysOrgCode("sys_role", sysCompany.getId());
		deleteBySysOrgCode("sys_permission", sysCompany.getId());
		deleteBySysOrgCode("sys_role_permission", sysCompany.getId());
		deleteBySysOrgCode("sys_position", sysCompany.getId());
		deleteBySysOrgCode("sys_catalog", sysCompany.getId());
		deleteBySysOrgCode("sys_quartz_job", sysCompany.getId());
		deleteBySysOrgCode("sys_depart", sysCompany.getId());
		deleteBySysOrgCode("sys_dict", sysCompany.getId());
		deleteBySysOrgCode("sys_dict_item", sysCompany.getId());
		deleteBySysOrgCode("sys_data_source", sysCompany.getId());
		deleteBySysOrgCode("sys_generate", sysCompany.getId());
		deleteBySysOrgCode("dyn_form", sysCompany.getId());
//        删除工作流
		sysCompanyMapper.deleteById(sysCompany.getId());
		//      删除报表文件
		File dir = new File(fileUrl + "/" + sysCompany.getId());
		if (dir.isDirectory() == false) {
			System.out.println("Not a directory. Do nothing");
			return;
		}
		File[] listFiles = dir.listFiles();
		for (File file : listFiles) {
			System.out.println("Deleting " + file.getName());
			file.delete();
		}
		dir.delete();
	}

	@Override
	public List<Map<String, String>> getCompanyName() {
		QueryWrapper queryWrapper = new QueryWrapper();
		List<SysCompany> sysCompanies = sysCompanyMapper.selectList(queryWrapper);
		List<Map<String, String>> dataList = Lists.newArrayList();
		for (SysCompany sysCompany : sysCompanies) {
			Map<String, String> map = Maps.newHashMap();
			map.put("label", sysCompany.getName());
			map.put("value", sysCompany.getId());
			dataList.add(map);
		}
		return dataList;
	}

	/**
	 * 根据sysOrgCode删除数据
	 *
	 * @param tableName
	 * @param sysOrgCode
	 * @return
	 */
	public Integer deleteBySysOrgCode(String tableName, String sysOrgCode) {
		String sql = "delete from " + tableName + " where sys_org_code = ?;";
		Integer i = jdbcTemplate.update(sql, sysOrgCode);
		return i;
	}

	@Override
	public List<Map<String, Object>> getUserLicences(String tenantId) {
		String sql = String.format("select *  from sys_company c where   c.id=?  and c.force_date <=CURDATE() and c.dead_date>=CURDATE()");
		List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, tenantId);
		return list;
	}

}
